import { exec } from 'node:child_process'
import fs from 'node:fs'
import path from 'node:path'
import { promisify } from 'node:util'

import { app } from 'electron'
import Logger from 'electron-log'
import iconv from 'iconv-lite' // 需要安装 iconv-lite 包

const execAsync = promisify(exec)

interface SearchResult {
  path: string
  name: string
  highlightedName?: string
  highlightedPath?: string
  isFolder: boolean
  size?: number
  dateModified?: string
}

export default class EverythingSearchService {
  private static esPath: string | null = null
  private static everythingPath: string | null = null
  private static isEverythingRunning: boolean = false
  private static lastCheckTime: number = 0
  private static CHECK_INTERVAL = 30000 // 30秒内不重复检查

  /**
   * 优化的Everything运行检查
   */
  private static async ensureEverythingRunningOptimized(): Promise<void> {
    const now = Date.now()

    // 如果最近检查过且确认在运行，跳过检查
    if (this.isEverythingRunning && now - this.lastCheckTime < this.CHECK_INTERVAL) {
      Logger.info('[EverythingSearchService] Everything recently verified as running, skipping check')
      return
    }

    // 执行检查
    await this.ensureEverythingRunning()
    this.isEverythingRunning = true
    this.lastCheckTime = now
  }

  /**
   * 初始化 Everything 搜索服务
   */
  public static init(): void {
    // 尝试查找 ES.exe 的路径
    this.findEsExecutable()
  }

  /**
   * 查找 ES.exe 可执行文件
   */
  private static findEsExecutable(): void {
    // 优先使用内置的Everything路径
    const appRoot = process.cwd()
    const builtinEsPath = path.join(appRoot, 'my_modules', 'plug-in', 'Everything', 'es.exe')
    const builtinEverythingPath = path.join(appRoot, 'my_modules', 'plug-in', 'Everything', 'Everything.exe')

    const commonPaths = [
      builtinEsPath, // 内置路径优先
      'C:\\Program Files\\Everything\\ES.exe',
      'C:\\Program Files (x86)\\Everything\\ES.exe',
      'C:\\Everything\\ES.exe',
      path.join(process.env.LOCALAPPDATA || '', 'Everything', 'ES.exe'),
      path.join(app.getPath('userData'), 'bin', 'ES.exe')
    ]

    Logger.info('[EverythingSearchService] Searching for ES.exe...')
    Logger.info(`[EverythingSearchService] App root: ${appRoot}`)
    Logger.info(`[EverythingSearchService] Builtin ES path: ${builtinEsPath}`)

    for (const esPath of commonPaths) {
      Logger.info(`[EverythingSearchService] Checking: ${esPath}`)
      try {
        const normalizedPath = path.resolve(esPath)
        Logger.info(`[EverythingSearchService] Normalized path: ${normalizedPath}`)

        if (fs.existsSync(normalizedPath)) {
          const stats = fs.statSync(normalizedPath)
          if (stats.isFile()) {
            this.esPath = normalizedPath

            // 如果使用内置路径，同时设置Everything.exe路径
            if (esPath === builtinEsPath) {
              this.everythingPath = builtinEverythingPath
              Logger.info(`[EverythingSearchService] Using builtin Everything at: ${builtinEverythingPath}`)
            }

            Logger.info(`[EverythingSearchService] Found ES.exe at: ${normalizedPath}`)
            return
          } else {
            Logger.warn(`[EverythingSearchService] Path exists but is not a file: ${normalizedPath}`)
          }
        } else {
          Logger.info(`[EverythingSearchService] File does not exist: ${normalizedPath}`)
        }
      } catch (error) {
        Logger.warn(`[EverythingSearchService] Error checking path ${esPath}: ${error}`)
      }
    }

    Logger.error('[EverythingSearchService] ES.exe not found in any location')
    this.esPath = null
    this.everythingPath = null
  }

  /**
   * 设置Everything配置以确保IPC启用
   */
  private static setupEverythingConfig(): void {
    if (!this.everythingPath) return
    const configPath = path.join(path.dirname(this.everythingPath), 'Everything.ini')
    try {
      // 检查配置文件是否存在
      if (!fs.existsSync(configPath)) {
        Logger.info('[EverythingSearchService] Creating Everything.ini config')

        // 创建基本配置确保IPC启用和后台运行
        const config = `[Everything]
enable_ipc=1
ipc_window_name=EVERYTHING
index_folder_size=1
index_file_size=1
index_date_modified=1
run_in_background=1
start_with_windows=0
minimize_to_tray=1
close_to_tray=1
show_tray_icon=0
startup_create_window=0
ntfs_index=1
folder_index=1
index_attributes=1
monitor_changes=1
force_rebuild=1
`
        fs.writeFileSync(configPath, config, 'utf8')
      } else {
        // 读取现有配置并确保IPC启用
        let config = fs.readFileSync(configPath, 'utf8')
        if (!config.includes('enable_ipc=1')) {
          config += '\nenable_ipc=1\n'
          fs.writeFileSync(configPath, config, 'utf8')
          Logger.info('[EverythingSearchService] Updated Everything.ini to enable IPC')
        }
      }
    } catch (error) {
      Logger.warn(`[EverythingSearchService] Failed to setup config: ${error}`)
    }
  }

  /**
   * 确保Everything主程序正在运行
   */
  private static async ensureEverythingRunning(): Promise<void> {
    if (!this.everythingPath) {
      Logger.info('[EverythingSearchService] Not using builtin Everything, skipping startup check')
      return
    }

    try {
      // 首先设置配置
      this.setupEverythingConfig()

      // 检查Everything是否已经在运行
      const { stdout } = await execAsync('tasklist /FI "IMAGENAME eq Everything.exe" /FO CSV')
      if (stdout.includes('Everything.exe')) {
        Logger.info('[EverythingSearchService] Everything is already running')
        // 测试Everything主程序是否可用
        try {
          // 检查主程序窗口是否存在
          const windowCheck = await execAsync(
            'tasklist /FI "IMAGENAME eq Everything.exe" /FI "WINDOWTITLE eq Everything" /FO CSV'
          )
          if (windowCheck.stdout.includes('Everything.exe')) {
            Logger.info('[EverythingSearchService] Everything main program is running and ready')
            return
          }
        } catch (testError) {
          Logger.warn('[EverythingSearchService] Everything main program test failed, restarting Everything')
          // 终止现有进程
          try {
            await execAsync('taskkill /F /IM Everything.exe')
            await new Promise((resolve) => setTimeout(resolve, 2000)) // 增加等待时间
          } catch (killError) {
            Logger.warn(`[EverythingSearchService] Failed to kill Everything: ${killError}`)
          }
        }
      }

      // 启动Everything主程序
      Logger.info(`[EverythingSearchService] Starting Everything from: ${this.everythingPath}`)

      // 使用spawn来启动Everything主程序，确保后台运行
      const { spawn } = require('child_process')
      const everythingProcess = spawn(this.everythingPath, ['-startup'], {
        detached: true,
        stdio: 'ignore',
        windowsHide: true // 在Windows上隐藏窗口
      })

      // 让进程在后台运行
      everythingProcess.unref()
      Logger.info('[EverythingSearchService] Everything main process started in background')

      // 等待主程序完全启动
      await new Promise((resolve) => setTimeout(resolve, 5000))

      // 等待Everything主程序完全启动
      let retries = 0
      const maxRetries = 10
      while (retries < maxRetries) {
        await new Promise((resolve) => setTimeout(resolve, 2000))
        try {
          // 检查主程序是否正在运行
          const processCheck = await execAsync('tasklist /FI "IMAGENAME eq Everything.exe" /FO CSV')
          if (processCheck.stdout.includes('Everything.exe')) {
            Logger.info('[EverythingSearchService] Everything main program started and ready')
            return
          }
        } catch (testError) {
          retries++
          Logger.info(
            `[EverythingSearchService] Everything startup check attempt ${retries}/${maxRetries} failed: ${testError}`
          )
        }
      }
      Logger.warn('[EverythingSearchService] Everything started but IPC may not be ready')
    } catch (error) {
      Logger.warn(`[EverythingSearchService] Error checking/starting Everything: ${error}`)
    }
  }

  /**
   * 使用 Everything 搜索文件
   */
  public static async searchFiles(
    _: Electron.IpcMainInvokeEvent,
    query: string,
    maxResults: number = 50
  ): Promise<SearchResult[]> {
    Logger.info(`[EverythingSearchService] Starting search for: "${query}"`)
    Logger.info(`[EverythingSearchService] Current esPath: ${EverythingSearchService.esPath}`)

    // 确保初始化
    if (!EverythingSearchService.esPath) {
      Logger.info('[EverythingSearchService] esPath is null/undefined, attempting to find ES.exe')
      EverythingSearchService.findEsExecutable()
      Logger.info(`[EverythingSearchService] After findEsExecutable, esPath: ${EverythingSearchService.esPath}`)
    }

    if (!EverythingSearchService.esPath) {
      const error =
        'Everything 搜索工具未找到。请确保已安装 Everything 搜索引擎并且 ES.exe 位于标准安装路径。\n\n请检查以下路径是否存在 ES.exe：\n- my_modules\\plug-in\\Everything\\es.exe\n- C:\\Program Files\\Everything\\ES.exe\n- C:\\Program Files (x86)\\Everything\\ES.exe'
      Logger.error(`[EverythingSearchService] ${error}`)
      throw new Error(error)
    }

    try {
      // 验证 ES.exe 文件是否仍然存在
      if (!fs.existsSync(EverythingSearchService.esPath)) {
        Logger.error(`[EverythingSearchService] ES.exe no longer exists at: ${EverythingSearchService.esPath}`)
        EverythingSearchService.esPath = null
        throw new Error('Everything 搜索工具路径无效，请重新安装 Everything')
      }

      // 使用优化的检查方法
      await EverythingSearchService.ensureEverythingRunningOptimized()

      // 构建搜索命令，添加UTF-8输出参数
      const command =
        maxResults > 0
          ? `chcp 65001 && "${EverythingSearchService.esPath}" -n ${maxResults} -p -r "${query}"`
          : `chcp 65001 && "${EverythingSearchService.esPath}" -p -r "${query}"`

      // 然后使用utf8编码
      // 删除未使用的result变量声明
      await execAsync(command, {
        encoding: 'utf8',
        shell: 'cmd' // 需要使用cmd shell来执行chcp命令
      })
      Logger.info(`[EverythingSearchService] Executing command: ${command}`)

      let stdout, stderr

      try {
        // 修改：使用buffer模式获取原始输出，然后手动转换编码
        const result = await execAsync(command, {
          encoding: 'buffer', // 改为buffer模式
          maxBuffer: 1024 * 1024 * 10 // 增加缓冲区大小到10MB
        })

        // 改进编码检测和转换
        let encoding = 'utf8'
        if (process.platform === 'win32') {
          // 尝试检测编码，优先使用 UTF-8，如果失败则使用 GBK
          try {
            stdout = iconv.decode(result.stdout, 'utf8')
            // 检查是否包含乱码字符
            if (stdout.includes('�') || !/[\u4e00-\u9fa5]/.test(stdout)) {
              throw new Error('UTF-8 decode failed')
            }
          } catch {
            encoding = 'gbk'
            stdout = iconv.decode(result.stdout, encoding)
          }
        } else {
          stdout = iconv.decode(result.stdout, 'utf8')
        }
        stderr = result.stderr ? iconv.decode(result.stderr, encoding) : ''
      } catch (error: any) {
        Logger.error(`[EverythingSearchService] Search command failed: ${error}`)
        // 减少重试等待时间
        Logger.warn('[EverythingSearchService] Attempting to restart Everything and retry')
        await EverythingSearchService.ensureEverythingRunning()

        // 减少等待时间从2秒到500毫秒
        await new Promise((resolve) => setTimeout(resolve, 500))

        // 重试一次，同样使用正确的编码
        try {
          const retryResult = await execAsync(command, {
            encoding: 'buffer',
            maxBuffer: 1024 * 1024 * 10
          })
          const encoding = process.platform === 'win32' ? 'gbk' : 'utf8'
          stdout = iconv.decode(retryResult.stdout, encoding)
          stderr = retryResult.stderr ? iconv.decode(retryResult.stderr, encoding) : ''
        } catch (retryError: any) {
          Logger.error(`[EverythingSearchService] Retry also failed: ${retryError}`)
          throw new Error(
            `Everything 搜索失败。请尝试：\n1. 手动启动 Everything 程序\n2. 检查 Everything 是否正确安装\n3. 重启应用程序\n\n详细错误: ${retryError.stderr || retryError.message}`
          )
        }
      }

      if (stderr) {
        Logger.error(`[EverythingSearchService] Command stderr: ${stderr}`)
        throw new Error(`搜索出错: ${stderr}`)
      }

      Logger.info(`[EverythingSearchService] Command stdout length: ${stdout.length}`)

      // 解析结果并添加高亮
      const results: SearchResult[] = []
      const lines = stdout.trim().split('\n')

      Logger.info(`[EverythingSearchService] Processing ${lines.length} result lines`)

      // 创建高亮函数
      // 创建高亮函数
      // 创建高亮函数
      const highlightText = (text: string, query: string): string => {
        if (!query || !text) return text
        // 移除查询中的特殊字符和引号
        const cleanQuery = query.replace(/["'*?]/g, '').trim()
        if (!cleanQuery) return text

        // 确保文本是正确的 UTF-8 编码
        const normalizedText = text.normalize('NFC')

        // 分割查询词
        const queryWords = cleanQuery.split(/\s+/).filter((word) => word.length > 0)
        let highlightedText = normalizedText

        // 对每个查询词进行高亮
        queryWords.forEach((word) => {
          const regex = new RegExp(`(${word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi')
          highlightedText = highlightedText.replace(regex, '<mark>$1</mark>')
        })
        return highlightedText
      }

      // 在解析结果后添加相关性排序
      for (const line of lines) {
        if (!line.trim()) continue

        // 解析行数据
        const filePath = line.trim()
        const name = path.basename(filePath)
        const highlightedName = highlightText(name, query)
        const highlightedPath = highlightText(filePath, query)

        let isFolder = false
        try {
          isFolder = fs.existsSync(filePath) && fs.lstatSync(filePath).isDirectory()
        } catch (error) {
          // 忽略错误，默认为文件
        }

        results.push({
          path: filePath,
          name,
          highlightedName,
          highlightedPath,
          isFolder
        })
      }

      // 按相关性排序
      const sortByRelevance = (results: SearchResult[], query: string): SearchResult[] => {
        const cleanQuery = query.toLowerCase().trim()

        return results.sort((a, b) => {
          const aName = a.name.toLowerCase()
          const bName = b.name.toLowerCase()

          // 1. 完全匹配文件名（不含扩展名）
          const aBaseName = path.parse(a.name).name.toLowerCase()
          const bBaseName = path.parse(b.name).name.toLowerCase()

          if (aBaseName === cleanQuery && bBaseName !== cleanQuery) return -1
          if (bBaseName === cleanQuery && aBaseName !== cleanQuery) return 1

          // 2. 文件名开头匹配
          const aStartsWith = aName.startsWith(cleanQuery)
          const bStartsWith = bName.startsWith(cleanQuery)

          if (aStartsWith && !bStartsWith) return -1
          if (bStartsWith && !aStartsWith) return 1

          // 3. 文件名包含匹配
          const aContains = aName.includes(cleanQuery)
          const bContains = bName.includes(cleanQuery)

          if (aContains && !bContains) return -1
          if (bContains && !aContains) return 1

          // 4. 路径匹配
          const aPathContains = a.path.toLowerCase().includes(cleanQuery)
          const bPathContains = b.path.toLowerCase().includes(cleanQuery)

          if (aPathContains && !bPathContains) return -1
          if (bPathContains && !aPathContains) return 1

          // 5. 按文件名长度排序（短的在前）
          return a.name.length - b.name.length
        })
      }

      const sortedResults = sortByRelevance(results, query)
      Logger.info(`[EverythingSearchService] Returning ${sortedResults.length} sorted results`)
      return sortedResults
    } catch (error) {
      Logger.error(`[EverythingSearchService] Search failed: ${error}`)
      throw error
    }
  }

  /**
   * 清理资源（应用退出时调用）
   */
  public static cleanup(): void {
    if (this.everythingPath) {
      Logger.info('[EverythingSearchService] Cleaning up Everything process')
      // 可以选择是否关闭Everything，通常让它继续运行更好
      // exec('taskkill /F /IM Everything.exe', () => {})
    }
  }
}
